<?php
namespace Admin\Controller;

use OSS\Core\OssException;
use OSS\Model\PrefixInfo;
use OSS\OssClient;
use Think\Controller;
Vendor('OSS.autoload');
use Think\Log;

set_time_limit(0);
class Oss2Controller extends AdminController
{
    private static  $URL_PREFIX = "https://duopu-img.oss-cn-shenzhen.aliyuncs.com/";
    
    public function _initialize()
    {
        $this->accessKeyId = C('OSS.accessKeyId');
        $this->accessKeySecret = C('OSS.accessKeySecret');
        $this->endpoint = C('OSS.endpoint');
        $this->bucket = C('OSS.bucket')['img'];
        $this->ossDomain = C('OSS.ossDomain')['img'];
    
        try {
            $this->oss = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
        } catch (OssException $e) {
            print $e->getMessage();
        }
        parent::_initialize();
    }
    
    /**
     * 列出Bucket内所有目录和文件, 注意如果符合条件的文件数目超过设置的max-keys， 用户需要使用返回的nextMarker作为入参，通过
     * 循环调用ListObjects得到所有的文件，具体操作见下面的 listAllObjects 示例
     *
     * @param OssClient $ossClient OssClient实例
     * @param string $bucket 存储空间名称
     * @return null
     */
    function listObjects($nextMarker)
    {
        $prefix = '';
        $delimiter = '/';
        $maxkeys = 100;
        $options = array(
            'delimiter' => $delimiter,
            'prefix' => $prefix,
            'max-keys' => $maxkeys,
            'marker' => $nextMarker,
        );
        try {
            $listObjectInfo = $this->oss->listObjects($this->bucket, $options);
        } catch (OssException $e) {
            printf(__FUNCTION__ . ": FAILED\n");
            printf($e->getMessage() . "\n");
            return;
        }
        return $listObjectInfo;
    }
    /**
     * 列出Bucket内所有目录和文件， 根据返回的nextMarker循环得到所有Objects
     *
     * @param OssClient $ossClient OssClient实例
     * @param string $bucket 存储空间名称
     * @return null
     */
    function listAllObjects($prefix)
    {
        //构造dir下的文件和虚拟目录
        $delimiter = '/';
        $nextMarker = '';
        $maxkeys = 30;
        
        while (true) {
            $options = array(
                'delimiter' => $delimiter,
                'prefix' => $prefix,
                'max-keys' => $maxkeys,
                'marker' => $nextMarker,
            );
            try {
                $listObjectInfo = $this->oss->listObjects($this->bucket, $options);
            } catch (OssException $e) {
                printf(__FUNCTION__ . ": FAILED\n");
                printf($e->getMessage() . "\n");
                return;
            }
            // 得到nextMarker，从上一次listObjects读到的最后一个文件的下一个文件开始继续获取文件列表
            $nextMarker = $listObjectInfo->getNextMarker();
            $listObject = $listObjectInfo->getObjectList();
            $listPrefix = $listObjectInfo->getPrefixList();
            //var_dump($listObject);
            foreach($listObject as $key => $val) {
               $objList[] = $val->getKey();
               
            }
            if ($nextMarker === '') {
                break;
            }
        }
        return $objList;
    }
    
    public function syncOssToServer(){
        Log::writeInfo('start to syncOssToServer','oss');
        $i=1;
        $nextMarker = '郑成河《Rylynn》指弹吉他谱_六线独奏谱/';
        while(true) {
            Log::writeInfo('loop: i='.$i++,'oss');
            Log::writeInfo('step-1: listObjects','oss');
            //step-1:获取曲谱和对应的图片列表
            $listObjectInfo = $this->listObjects($nextMarker);
            $prefixList = $listObjectInfo->getPrefixList(); // 目录列表
            $nextMarker = $listObjectInfo->getNextMarker();
            if (!empty($prefixList)) {
                foreach ($prefixList as $prefixInfo) {
                    $prefix = $prefixInfo->getPrefix();
                    $objList[$prefix] = $this->listAllObjects($prefix);
                }
            }
            Log::writeInfo('nextMarker: '.json_encode($nextMarker),'oss');
            //step-2: 处理曲谱缺失的情况
            Log::writeInfo('step-2: processSheet','oss');
            $this->processSheet($objList);
            //step-3: 处理图片缺失的情况
            Log::writeInfo('step-3: processImage','oss');
            $this->processImage($objList);
            
            //step-4: 处理图片和曲谱关系缺失的情况
            Log::writeInfo('step-4: processImageSheet','oss');
            $this->processImageSheet($objList);
            
            if($nextMarker === '') {
                echo "finished".'<br/>';
                break;
            }
            unset($objList);
            sleep(1);
        }
        Log::writeInfo('end to syncOssToServer','oss');
    }
    
    private function processImage($dirList){
        foreach ($dirList as $key=>$objList) {
            foreach ($objList as $objKey => $val) {
                $dirList[$key][$objKey] = self::$URL_PREFIX.$val;
                $images[] = self::$URL_PREFIX.$val;
            }
        }
        
        //找出不存在于数据库中的记录
        $model = M('image');
        $map = array(
            'url' => array('in', $images)
        );
        
        //print_r($images);exit;
        $imageInDb = $model->field('url')->where($map)->select();
        $imageInDb = empty($imageInDb)? array() : $imageInDb;
        
        $existImages = array_column($imageInDb, "url");
        
        foreach ($dirList as $key => $objList) {
            foreach ($objList as $objKey=>$val) {
                if(in_array($val, $existImages)) {
                    unset($dirList[$key][$objKey]);
                    continue;
                }
            
                
                $imageParam[] = array(
                    'name' => explode('/',$val)[4],
                    'url' => $val,
                    'creator' => 2,
                    'img_type' => 10
                );
                
            }
        }
        if(!empty($imageParam)) {
            Log::writeInfo('step-3-1: save_images '.json_encode($imageParam),'oss');
            $rowCount = $model->addAll($imageParam);
            unset($imageParam);
        }
        
    }
    
    private function processImageSheet($dirList){
        foreach ($dirList as $key=>$objList) {
            foreach ($objList as $objKey => $val) {
                $dirList[$key][$objKey] = self::$URL_PREFIX.$val;
            }
        }
        
        $urls = array();
        foreach ($dirList as $key=>$objList) {
            $sheetNames[] = explode('/', $key)[0];
            foreach ($objList as $objKey=>$val) {
                array_push($urls, $val);
            }

        }
        
        $sheetModel = M('Sheet');
        $map = array(
            'name' => array('in', $sheetNames)
        );
        $sheetInDb = $sheetModel->field('id,name')->where($map)->select();
        $sheetInDb = empty($sheetInDb) ? array() : $sheetInDb;
        
        $sheetMap = array();
        foreach ($sheetInDb as $key=>$val) {
            $sheetMap[$val['name'].'/'] = $val['id'];
        }
        
        $imageModel = M('image');
        $map = array(
            'url' => array('in', $urls)
        );
        $imageInDb = $imageModel->field('id, url')->where($map)->select();
        $imageInDb = empty($imageInDb) ? array() : $imageInDb;
        $imageMap = array();
        foreach ($imageInDb as $key=>$val) {
            $imageMap[$val['url']] = $val['id'];
        }


        foreach ($dirList as $key => $objList) {
            foreach ($objList as $objKey=>$val) {
                if(empty($imageMap[$val]) || empty($sheetMap[$key])) {
                    continue;
                }
                $imageSheet[] = array(
                    "image_id"  => $imageMap[$val],
                    "sheet_id"  => $sheetMap[$key],
                    "index"  => $objKey+1,
                    'creator' => 2,
                );
            }
        }
        if(!empty($imageSheet)) {
            $map['sheet_id'] = array('in', array_column($sheetInDb, "id"));
            M('imageSheet')->where($map)->delete();
            Log::writeInfo('step-3-2-1: save_images_sheet '.json_encode($imageSheet),'oss');
            M('imageSheet')->addAll($imageSheet);
            unset($imageSheet);
        }
        
    }
    
    
    /**
     * 处理曲谱缺失的情况
     */
    private function processSheet($objList){
        //去掉目录名字最后的"/"
        $ossDirNames = array_keys($objList);
        foreach ($ossDirNames as $val) {
            $sheetNames[] = substr($val,0,strlen($val)-1);
        }
        
        //获取的结果到数据库中查询
        $map = array(
            'name' => array('in', $sheetNames)
        );
        
        $model = M('Sheet');
        $sheetInDb = $model->field('name')->where($map)->select();
        $sheetInDb = empty($sheetInDb) ? array() : $sheetInDb;
        
        $existNames = array_column($sheetInDb, "name");
        $notExistData = array_diff($sheetNames, $existNames);
        
        foreach ($notExistData as $key => $val) {
            $sheetParam[] = array(
                'name' => $val,
                'creator' => 2,
                'author_type' => 10
            );
        }
        
        if(!empty($sheetParam)) {
            Log::writeInfo('step-2-1: save_sheet '.json_encode($sheetParam),'oss');
            $model->addAll($sheetParam);
            unset($sheetParam);
        }
    }
}

